package com.nariano.server.domain.engine;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;


import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.timer.TimerTaskExecutor;

import com.nariano.server.domain.engine.Engine;

public abstract class RoundBasedEngine implements Engine {
	
    
    Logger logger = Logger.getLogger(RoundBasedEngine.class);

    @Autowired
    @Qualifier(value = "executor")
    TimerTaskExecutor executor;
    private int FAIL_STATE_ROUND_DELAY_MILLISECONDS = 3600*1000;
    private int configuredRoundDelay;
    private int effectiveRoundDelay;

    public RoundBasedEngine() {
        super();
    }

    public void setDelay(int delay) {
    	configuredRoundDelay = delay;
        effectiveRoundDelay = delay;
    }
    
    public final void run() {
    	try {
    		Date start = new Date();
    		logger.info("Engine job started at " + format(start));
    		doRun();
    		Date stop = new Date();
    		logger.info("Engine job finished at " + format(stop) + " in " + (stop.getTime()-start.getTime()) + " ms");
    		setSuccessState();
    	} catch(Exception e) {
    		logger.warn("Fail state",e);
    		setSuccessFail();
    	}
    	start();
    }

    private void setSuccessFail() {
    	effectiveRoundDelay = FAIL_STATE_ROUND_DELAY_MILLISECONDS;
	}

	private void setSuccessState() {
		effectiveRoundDelay = configuredRoundDelay;
	}

	protected abstract void doRun();

    public void start() {
        logger.info("Engine started " + format(new Date()));
        executor.setDelay(effectiveRoundDelay);
        executor.execute(this);
    }

    protected String format(Date date) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        return String.format("%d-%d-%d %d:%d:%d %d", c.get(Calendar.YEAR)
                                               , c.get(Calendar.MONTH)
                                               , c.get(Calendar.DAY_OF_MONTH)
                                               , c.get(Calendar.HOUR_OF_DAY)
                                               , c.get(Calendar.MINUTE)
                                               , c.get(Calendar.SECOND)
                                               , c.get(Calendar.MILLISECOND));
    }

}